package com.media.entrance.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.media.entrance.controller.CustomerController;
import com.media.entrance.controller.DiscoveryController;
import com.media.entrance.utils.MediaEntranceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.validation.constraints.Null;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@Deprecated
public class MediaCustomerService {
    @Autowired
    private DiscoveryController discoveryController;

    @NacosInjected
    private NamingService namingService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RestTemplate restTemplate;

    //设置redis数据，并设置任意超时（秒），0为不超时
    public void setInfoRedis(String key, String result, int timeoutSeconds){
        stringRedisTemplate.opsForValue().set(key, result);
        if (timeoutSeconds > 0) {
            stringRedisTemplate.expire(key, timeoutSeconds, TimeUnit.SECONDS);
        }
    }
    // 获取redis数据
    public String getFromRedis(String key) {
        Boolean haskey;
        try {
            haskey = stringRedisTemplate.hasKey(key);
        } catch (NullPointerException e) {
            log.error(e.getMessage());
            return null;
        }
        return (Boolean.TRUE.equals(haskey)) ? stringRedisTemplate.opsForValue().get(key) : null;
    }

    //清理key
    public Boolean clearKeyInRedis(String key) {
        Boolean haskey;
        try {
            haskey = stringRedisTemplate.hasKey(key);
            if (Boolean.TRUE.equals(haskey)) {
                return stringRedisTemplate.delete(key);
            }
        } catch (NullPointerException e) {
            log.error(e.getMessage());
            return null;
        }
        return false;
    }

    // 步骤1：获取匹配的坐席，如果获取不到直接返回
    // 测试flag true 获得匹配，false没有匹配
    public JSONObject getAgentInfo(boolean hasIdleAgent){
        JSONObject result = new JSONObject();
        if (hasIdleAgent) {
            result.put("agentId", "2022100890");
            result.put("queueNo", 0);
        } else {
            result.put("agentId", null);
            result.put("queueNo", 5);
        }
        return result;
    }

    // 步骤2：获取媒体服务的INFO
    public JSONObject getMediaServiceInfo(final String type, final String serviceName, final int timeout) {
        String redisResult = getFromRedis(type);
//        Date date = new Date();
        if (redisResult != null) {
            JSONObject redisInfo = JSONObject.parseObject(redisResult);
            log.info("getMediaServiceInfo get direct redisInfo return : [" +  redisInfo.toJSONString() + "]");
            JSONObject resultInfo = processServerInfo(redisInfo, type);
            log.info("getMediaServiceInfo get direct resultInfo return : [" +  resultInfo.toJSONString() + "]");
            return resultInfo;
//            // 判断更新时间小于2s
//            long current = date.getTime();
//            long lastUpdateTime = Long.parseLong(redisInfo.get("updateTime").toString());
//            if (current - lastUpdateTime <= 2000){
//                return processForwardInfo(redisInfo);
//            }
        }

        // 通过nacos获取所有健康的实例信息
        List<Instance> sfusInfo = getNacosHealthServiceInfo(serviceName, true);

        // 如果没有健康的服务实例
        if (sfusInfo.size() == 0) {
            return new JSONObject();
        }
        JSONObject redisRecord = new JSONObject();
        redisRecord.put(type, new JSONArray());
        for (Instance instance : sfusInfo) {
            // 请求每个转发服务器上的信息
            String uri = "http://" + instance.getIp() + ":" + instance.getPort() + "/media/server/" + type;
            System.out.println("get uri info " + uri);
            HttpHeaders httpHeaders = new HttpHeaders();
            MediaType mediaType = MediaType.parseMediaType("application/json;charset=UTF-8");
            httpHeaders.setContentType(mediaType);
            HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<>(httpHeaders);
            ResponseEntity<String> apiResponse = restTemplate.exchange(uri, HttpMethod.GET, formEntity, String.class);

            // 构造数据
            JSONObject getResult = JSONObject.parseObject(apiResponse.getBody());
            log.info("getMediaServiceInfo get nacos single result :[" + uri + "] return : [" +  getResult.toJSONString() + "]");
            getResult.put("serverUrl", instance.getIp() + ":" + instance.getPort());
            redisRecord.getJSONArray(type).add(getResult);
        }
        // 更新到redis中
//        long currentWrite = date.getTime();
//        redisRecord.put("updateTime", String.valueOf(currentWrite));
        setInfoRedis(type, redisRecord.toJSONString(), timeout);

        // 返回结果
        log.info("getMediaServiceInfo get nacos total result :[" +  redisRecord.toJSONString() + "]");
        JSONObject resultInfo = processServerInfo(redisRecord, type);
        log.info("getMediaServiceInfo get direcet resultInfo return : [" +  resultInfo.toJSONString() + "]");
        return resultInfo;
    }

    // 将redis得到的结果重新分配并更新到redis
    public boolean needRedistribute(String redisResult, String tagName, String serviceName) {
        List<Instance> serviceInfo = getNacosHealthServiceInfo(serviceName, true);
        JSONObject redisInfo = JSONObject.parseObject(redisResult);
        if (redisInfo.containsKey(tagName)) {
            JSONObject service = redisInfo.getJSONObject(tagName);
            if (service.containsKey("serverUrl")) {
                String url = service.getString("serverUrl");
                return isUrlInNacosInstance(serviceInfo, url);
            } else {
                log.warn(redisInfo.toJSONString() + "maybe the key:[" + tagName + "] has nothing with serverUrl!");
                return false;
            }
        } else {
            throw new MediaEntranceException(redisInfo.toJSONString() + "not contain" + tagName);
        }
    }
    // 处理nacos中返回的是否包含制定的IP PORT
    public boolean isUrlInNacosInstance(List<Instance> nacosInstance, String url) {
        if (nacosInstance.size() == 0) {
            log.error("nacos get no health service!");
            return true;
        }
        for (Instance instance : nacosInstance) {
            String instanceUri = instance.getIp() + ":" + instance.getPort();
            if (instanceUri.equals(url)) {
                return false;
            }
        }
        return true;
    }
    // 获取nacos中的的servicename的实例，便于分配
    public List<Instance> getNacosHealthServiceInfo(String serviceName, boolean isHealth) {
        List<Instance> sfusInfo;
        try {
            sfusInfo = namingService.selectInstances(serviceName, isHealth);
            log.info("getNacosHealthServiceInfo get nacos healthStatus:[" +isHealth + "service:[" + serviceName + "] return : [" +  sfusInfo.toString() + "]");
            return sfusInfo;
        } catch (NacosException e) {
            log.error("getNacosHealthServiceInfo get NacosException error: [" +  e + "]");
            return new ArrayList<>();
        }
    }
    // 获取jsonarray中的innerKeyName的最小值的索引号
    private String getMinKeyInJSONObject(JSONObject inputInfo){
        int minIndexTotal = Integer.MAX_VALUE;
        String minKey = "";
        HashMap<String, Integer> countMap = JsonObjectToHashMap(inputInfo);
        for (String key: countMap.keySet()) {
            if (countMap.get(key) < minIndexTotal) {
                minIndexTotal = countMap.get(key);
                minKey = key;
            }
        }
        return minKey;
    }
    // 转换jsonobject to hashmap
    private HashMap<String, Integer> JsonObjectToHashMap(JSONObject jsonObj){
        HashMap<String, Integer> data = new HashMap<>();
        for (String s : jsonObj.keySet()) {
            Integer value = jsonObj.getIntValue(s);
            data.put(s, value);
        }
        return data;
    }

    // 获取数组中的最小值的index
    private int getMinInArray(JSONArray inputInfo){
        int minIndexTotal = Integer.MAX_VALUE;
        int recordIndex = -1;
        for (int i = 0; i < inputInfo.size(); i++) {
            int count = inputInfo.getJSONObject(i).getIntValue("totalNumber");
            if (count < minIndexTotal) {
                minIndexTotal = count;
                recordIndex = i;
            }
        }
        return recordIndex;
    }

    // 处理返回的数据
    private JSONObject processServerInfo(JSONObject inputInfo, String type){
        JSONObject result = new JSONObject();
        //获取所有的转发信息，找到总房间数最少的转发url
        JSONArray tempTotal = inputInfo.getJSONArray(type);
        int recordIndex = getMinInArray(tempTotal);

        //在总房间数最少的转发里找每个CPU核心上最少的房间索引
        JSONObject tempWorkers = tempTotal.getJSONObject(recordIndex).getJSONObject("everyCoreInfo");
        String coreId = getMinKeyInJSONObject(tempWorkers);

        // 将结果放到result中返回
        String serverUrl = tempTotal.getJSONObject(recordIndex).getString("serverUrl");
        result.put("serverUrl", serverUrl);
        result.put("coreId", coreId);
        return result;
    }
}
